<template lang="html">
  <div class="wrapper">
    <canvas id="canvas" width="560" height="350"></canvas>
  </div>
</template>

<script>

export default {
  methods: {
    init () {
      const physics_accuracy = 3,
        mouse_influence = 20,
        mouse_cut = 5,
        gravity = 1200,
        cloth_height = 30,
        cloth_width = 50,
        start_y = 20,
        spacing = 7,
        tear_distance = 60

      window.requestAnimFrame =
        window.requestAnimationFrame ||
        window.webkitRequestAnimationFrame ||
        window.mozRequestAnimationFrame ||
        window.oRequestAnimationFrame ||
        window.msRequestAnimationFrame ||
        function (callback) {
            window.setTimeout(callback, 1000 / 60);
        }

      let canvas,
        ctx,
        cloth,
        boundsx,
        boundsy,
        mouse = {
          down: false,
          button: 1,
          x: 0,
          y: 0,
          px: 0,
          py: 0
        }

      let Point = function (x, y) {
        this.x = x
        this.y = y
        this.px = x
        this.py = y
        this.vx = 0
        this.vy = 0
        this.pin_x = null
        this.pin_y = null

        this.constraints = []
      }

      Point.prototype.update = function (delta) {
        if (mouse.down) {
          let diff_x = this.x - mouse.x,
            diff_y = this.y - mouse.y,
            dist = Math.sqrt(diff_x * diff_x + diff_y * diff_y)

          if (mouse.button == 1) {
            if (dist < mouse_influence) {
              this.px = this.x - (mouse.x - mouse.px) * 1.8
              this.py = this.y - (mouse.y - mouse.py) * 1.8
            }
          } else if (dist < mouse_cut) this.constraints = []
        }
        this.add_force(0, gravity)

        delta *= delta
        let nx = this.x + ((this.x - this.px) * .99) + ((this.vx / 2) * delta)
        let ny = this.y + ((this.y - this.py) * .99) + ((this.vy / 2) * delta)

        this.px = this.x
        this.py = this.y

        this.x = nx
        this.y = ny

        this.vy = this.vx = 0
      };

      Point.prototype.draw = function () {
        if (!this.constraints.length) return
        var i = this.constraints.length
        while (i--) this.constraints[i].draw()
      };

      Point.prototype.resolve_contraints = function () {
        if (this.pin_x != null && this.pin_y != null) {
          this.x = this.pin_x
          this.y = this.pin_y
          return
        }

        let i = this.constraints.length
        while (i--) this.constraints[i].resolve()

        this.x > boundsx ? this.x = 2 * boundsx - this.x : 1 > this.x && (this.x = 2 - this.x)
        this.y < 1 ? this.y = 2 - this.y : this.y > boundsy && (this.y = 2 * boundsy - this.y)
      };

      Point.prototype.attach = function (point) {
        this.constraints.push(
          new Constraint(this, point)
        )
      };

      Point.prototype.resolve_constraints = function (constraint) {
        this.constraints.splice(this.constraints.indexOf(constraint), 1)
      };

      Point.prototype.add_force = function (x, y) {
        this.vx += x
        this.vy += y
      };

      Point.prototype.pin = function (pinx, piny) {
        this.pin_x = pinx
        this.pin_y = piny
      };

      let Constraint = function (p1, p2) {
        this.p1 = p1
        this.p2 = p2
        this.length = spacing
      }

      Constraint.prototype.resolve = function () {
        let diff_x = this.p1.x - this.p2.x,
          diff_y = this.p1.y - this.p2.y,
          dist = Math.sqrt(diff_x * diff_x + diff_y * diff_y),
          diff = (this.length - dist) / dist

        if (dist > tear_distance) this.p1.remove_contraint(this)

        let px = diff_x * diff * 0.5
        let py = diff_y * diff * 0.5

        this.p1.x += px
        this.p1.y += py
        this.p2.x -= px
        this.p2.y -= py
      };

      Constraint.prototype.draw = function () {
        ctx.moveTo(this.p1.x, this.p1.y)
        ctx.lineTo(this.p2.x, this.p2.y)
      };

      let Cloth = function () {
        this.points = []
        let start_x = canvas.width / 2 - cloth_width * spacing / 2

        for (let y = 0, y_len = cloth_height; y <= y_len; y++) {
          for (let x = 0, x_len = cloth_width; x <= x_len; x++) {
            let p = new Point(start_x + x * spacing, start_y + y * spacing)

            x != 0 && p.attach(this.points[this.points.length - 1])
            y == 0 && p.pin(p.x, p.y)
            y != 0 && p.attach(this.points[x + (y - 1) * (cloth_width + 1)])

            this.points.push(p)
          }
        }
      }

      Cloth.prototype.update = function () {
        let i = physics_accuracy

        while (i--) {
          var p = this.points.length
          while (p--) {
            this.points[p].resolve_constraints()
          }
        }

        i = this.points.length
        while (i--) this.points[i].update(.016)
      };

      Cloth.prototype.draw = function () {
        ctx.beginPath()

        let i = cloth.points.length
        while (i--) cloth.points[i].draw()

        ctx.stroke()
      };

      function update () {
        ctx.clearRect(0, 0, canvas.width, canvas.height)
        cloth.update()
        cloth.draw()
        requestAnimFrame(update)
      }

      function start () {
        canvas.onmousedown = function (e) {
          mouse.button = e.which
          mouse.px = mouse.x
          mouse.py = mouse.y
          let rect = canvas.getBoundingClientRect()
          mouse.x = e.clientX - rect.left
          mouse.y = e.clientY - rect.top
          mouse.down = true
          e.preventDefault()
        }

        canvas.onmouseup = function (e) {
          mouse.down = false
          e.preventDefault()
        }

        canvas.onmousemove = function (e) {
          mouse.px = mouse.x
          mouse.py = mouse.y
          let rect = canvas.getBoundingClientRect()
          mouse.x = e.clientX - rect.left
          mouse.y = e.clientY - rect.top
          e.preventDefault()
        }

        canvas.oncontextmenu = function (e) {
          e.preventDefault()
        }

        boundsx = canvas.width - 1
        boundsy = canvas.height  - 1

        ctx.strokeStyle = '#888'

        cloth = new Cloth()

        update()
      }
      // window.onload = function () {
      setTimeout(() => {
        canvas = document.getElementById('canvas')
        ctx = canvas.getContext('2d')
        canvas.width = 560
        canvas.height = 350

        start()

      })
      // }
    }
  },
  mounted () {
    this.init()
  }
}
</script>

<style lang="css" scoped>
* {
    margin: 0;
    overflow: hidden;
    -webkit-user-select: none;
    -moz-user-select: none;
    -ms-user-select: none;
    -o-user-select: none;
    user-select: none;
}
body {
    background: #f8f8f8;
}
#canvas {
    display: block;
    margin: 20px auto 0;
}
#info {
    position: absolute;
    left: -1px;
    top: -1px;
    width: auto;
    max-width: 420px;
    height: auto;
    background: #f2f2f2;
    border-bottom-right-radius: 10px;
    border:1px solid #333;
}
#top {
    background: #fff;
    width: 100%;
    height: auto;
    position: relative;
    border-bottom: 1px solid #eee;
}
p {
    font-family: Arial, sans-serif;
    color: #666;
    text-align: justify;
    font-size: 16px;
    margin: 10px 16px;
}
#github {
  color:#3377ee;
  font-family: Helvetica, Arial, sans-serif;
  font-size: 19px;
  display: block;
  margin: 0 auto;
  text-align: center;
  text-decoration:none;
}
#net {
  text-align:center;
  white-space:nowrap;
  font-size:19px;
  background:rgba(0,0,0,0.1);
  padding:8px 12px;
  border-radius:8px;
  display:block;
  color:#888;
}
#net > span {
  color:#3377ee;
  font-family: Helvetica, Arial, sans-serif;
  font-size: 14px;
  display: block;
  margin: 0 auto;
  text-align: center;
  text-decoration:none;
}
a {
    font-family: sans-serif;
    color: #444;
    text-decoration: none;
    font-size: 20px;
}
#site {
    float: left;
    margin: 10px;
    color: #ff9900;
  border-bottom: 1px dashed #ccc;
  padding-bottom:3px
}
#site:hover {
    color: #ffaa11;
}
#close {
    float: right;
    margin: 10px;
}
#p {
    font-family: Verdana, sans-serif;
    position: absolute;
    right: 10px;
    bottom: 10px;
    color: #4099ff;
    border: 1px dashed #4099ff;
    padding: 4px 8px;
}

#irc {
  display: block;
   text-align: center;
  margin-top:4px;
    color: #333;
}

#irc a {
  color: #3377ee;
  font-size: 17px
}

#irc-info {
  display: block;
  text-align: center;
  font-size: 14px;
  margin-top: -10px;
  color: #828282;
  margin-bottom:4px
}

#new {
  width: 100%;
  text-align: center;
  font-size: 18px;
  font-family: Helvetica;
}

#new a {
  font-size: 18px;
  color: #4099ff;
}
</style>
